package com.example.game_logic;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Log;
import android.util.Xml;

import com.example.game_logic.Color.ColorID;

public class Grid  extends Observable{

	protected Bloc[][] blocs_;
	protected Bloc lastAddedBloc_;

	protected List<Line> lines_;

	protected boolean lineInModification_;
	protected boolean lineCompleted_;

	protected int sizeGrid_;

	protected InputStream levelStream_;

	public Grid(int size, InputStream level)
	{
		sizeGrid_ = size;
		levelStream_ = level;
		blocs_ = new Bloc[sizeGrid_][sizeGrid_];
		lastAddedBloc_ = null;
		lineInModification_ = false;
		lineCompleted_ = false;
		lines_ = new ArrayList<Line>();

		for (int i = 0 ; i < sizeGrid_ ; i++)
		{
			for (int j = 0 ; j < sizeGrid_ ; j++)
			{
				blocs_[i][j] = null;
			}
		}

	}

	public boolean blocOnTouch(int x, int y)
	{		
		Bloc tempBloc = blocs_[x][y];

		// Cas ou l'on COMMENCE a glisser le doigt sur la grille
		if (!lineInModification_)
		{
			return blocOnTouchStart(tempBloc);
		}

		if (lineCompleted_)
			return false;

		// Cas lorsqu'on CONTINUE a glisser le doigt sur la grille
		if (lastAddedBloc_.addChild(tempBloc))
		{
			lastAddedBloc_ = tempBloc;
			if (tempBloc.isExtremity())
			{
				lineCompleted_ = true;
			}
			setChanged();
			notifyObservers();
		}

		return true;
	}

	protected boolean blocOnTouchStart(Bloc bloc)
	{
		// Cas bloc normal non utilise
		if (!bloc.isExtremity() && !bloc.isUsed())
		{
			lineCompleted_ = true;
			lineInModification_ = true;
			return false;
		}

		if (bloc.isExtremity())
		{
			Bloc tempExt = bloc.getLine().getStartBloc();
			if (tempExt != null)
			{
				tempExt.removeChildren();
			}
			bloc.setStartBloc();
		}

		bloc.removeChildren();

		lastAddedBloc_ = bloc;
		lineInModification_ = true;
		lineCompleted_ = false;
		
		setChanged();
		notifyObservers();
		return true;
	}

	public boolean blocOnTouchRelease()
	{
		// TODO : valider la modification (ajouter valeur temp...)
		lastAddedBloc_ = null;
		lineInModification_ = false;
		lineCompleted_ = false;
		return true;
	}	

	public boolean isGridComplete()
	{
		// Verification que les lignes sont tous complete
		for (Line line : lines_)
		{
			if (!line.isLineComplete())
			{
				return false;
			}
		}

		// Verification que les blocs sont tous utilises
		for (int i = 0 ; i < sizeGrid_ ; i++)
		{
			for (int j = 0 ; j < sizeGrid_ ; j++)
			{
				if (!blocs_[i][j].isUsed())
				{
					return false;
				}
			}
		}

		return true;
	}
	
	public int getNumberCompleteLine()
	{
		int retour = 0;
		for (Line line : lines_)
		{
			if (line.isLineComplete())
			{
				retour++;
			}
		}
		return retour;
	}
	
	public int getNumberOfLine()
	{
		return lines_.size();
	}

	public void restartLevel()
	{
		for (int i = 0 ; i < sizeGrid_ ; i++)
		{
			for (int j = 0 ; j < sizeGrid_ ; j++)
			{
				blocs_[i][j].setUnused();
			}
		}
		setChanged();
		notifyObservers();
	}

	public Bloc getLastAddedBloc()
	{
		return lastAddedBloc_;
	}

	public Bloc getBloc(int x, int y)
	{
		return blocs_[x][y];
	}
	
	public boolean loadLevel()
	{
		Document doc_ = null;
		try 
		{
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			doc_ = docBuilder.parse(new InputSource(levelStream_));

		}

		catch (ParserConfigurationException e) {e.printStackTrace();}
		catch (IOException e) {e.printStackTrace();}
		catch (SAXException e) {e.printStackTrace();}

		doc_.getDocumentElement().normalize();

		Node gridNode = doc_.getElementsByTagName("Grille").item(0);
		Element gridElement = (Element) gridNode;

		// Verification si le fichier correspond a la grandeur de la grille
		
		int Size = Integer.decode(gridElement.getAttribute("taille"));
		if (Size != sizeGrid_)
		{ 
			return false;					
		}
		
		// Ajouter tous les blocs d'extremites
		NodeList lineList = doc_.getElementsByTagName("Ligne");
		int numberLines = lineList.getLength();
		for (int k = 0 ; k < lineList.getLength() ; k++)
		{
			Node LineNode = lineList.item(k);

			if (LineNode.getNodeType() == Node.ELEMENT_NODE) 
			{
				Element lineElement = (Element) LineNode;
				if (!addLine(lineElement))
				{
					return false;
				}
			}
		}
		
		// Ajoute le reste des blocs qui ne sont pas des extremites
		for (int i = 0 ; i < sizeGrid_ ; i++)
		{
			for (int j = 0 ; j < sizeGrid_ ; j++)
			{
				if (blocs_[i][j] == null)
				{
					blocs_[i][j] = new Bloc(i, j, false);
				}
			}
		}

		return true;
	}
	
	/*
	 * Ajoute les ligne a la grille a partir d'un element XML
	 */
	private boolean addLine(Element element)
	{
		Color color = new Color(element.getAttribute("couleur"));
		Line newLine = new Line(color);
		
		NodeList ptsList = element.getElementsByTagName("Point");
		for (int i = 0 ; i < ptsList.getLength() ; i++)
		{
			Node pointNode = ptsList.item(i);
			if (pointNode.getNodeType() == Node.ELEMENT_NODE) 
			{
				Element pointElement = (Element) pointNode;
				
				int coordX = Integer.decode(pointElement.getAttribute("X"));
				coordX--;
				int coordY = Integer.decode(pointElement.getAttribute("Y"));
				coordY--;
				
				if (coordX > sizeGrid_-1 || coordY > sizeGrid_-1)
				{
					return false;
				}
				
				// Ajout du bloc a la grille et a la ligne
				Bloc tempBloc = new Bloc(coordX, coordY, true);
				
				newLine.addExtremityBloc(tempBloc);	// c'est la ligne qui gere la couleur du bloc
				blocs_[coordX][coordY] = tempBloc;
			}
		}
		lines_.add(newLine);
		
		return true;
	}
	
	public void testLoad()
	{
		Color color = new Color("rouge");
		Line newLine = new Line(color);

		// Ajout du bloc a la grille et a la ligne
		Bloc tempBloc1 = new Bloc(3, 3, true);
		Bloc tempBloc2 = new Bloc(6, 6, true);

		newLine.addExtremityBloc(tempBloc1);	// c'est la ligne qui gere la couleur du bloc
		newLine.addExtremityBloc(tempBloc2);
		blocs_[3][3] = tempBloc1;
		blocs_[6][6] = tempBloc2;
	}

}
